package com.wwj.server.notify;

import com.google.gson.Gson;
import com.wwj.core.server.entity.GameServer;
import com.wwj.core.server.entity.NotifyServer;
import com.wwj.core.server.service.INotifyServerService;
import com.wwj.server.codc.MessageDecoder;
import com.wwj.server.codc.MessageEncoder;
import com.wwj.server.notify.msg.NotifyMachineStatusMsg;
import com.wwj.server.notify.session.SessionManager;
import com.wwj.utils.IpUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.annotation.Resource;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class Server {

    private Logger logger = LoggerFactory.getLogger(getClass());

    public static final String PREFIX_DEVICE_MAP = "Device@";

    public static final ConcurrentHashMap<String, LinkedHashSet<String>> deviceMap = new ConcurrentHashMap<>();

    public static boolean flag = true;

    @Resource
    private JedisPool jedisPool;

    @Resource
    private INotifyServerService notifyServerService;

    /**
     * 启动
     */
    public void start(String serverName, int port) {

        // 服务类
        ServerBootstrap b = new ServerBootstrap();

        // 创建boss和worker
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            // 设置循环线程组事例
            b.group(bossGroup, workerGroup);

            // 设置channel工厂
            b.channel(NioServerSocketChannel.class);

            // 设置管道
            b.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new IdleStateHandler(60, 0, 0));
                    ch.pipeline().addLast(new MessageEncoder());
                    ch.pipeline().addLast(new MessageDecoder());
                    ch.pipeline().addLast(new ServerHandler());

                }
            });

//            b.option(ChannelOption.SO_BACKLOG, 2048)// 链接缓冲池队列大小
//                    .childOption(ChannelOption.SO_KEEPALIVE, true);// 启用心跳保活机制

            b.option(ChannelOption.SO_BACKLOG, 2048);// 链接缓冲池队列大小

            // 绑定端口
            b.bind(port).sync();

            NotifyServer notifyServer = notifyServerService.findByServerName(serverName);
            if (null == notifyServer) {
                notifyServer = new NotifyServer(serverName, IpUtil.getHostIp(), port);
                notifyServerService.createNewServer(notifyServer);
            } else {
                notifyServer.setIp(IpUtil.getHostIp());
                notifyServer.setPort(port);
                notifyServer.setIsOnline(GameServer.ONLINE);
                notifyServerService.updateServer(notifyServer);
            }
            logger.info("NotifyServer服务端已启动,监听端口：{}", port);

            //从redis中获取支付队列，发送机器占用状态信息
            new Thread(new Runnable() {
                @Override
                public void run() {
                    logger.debug("启动监听redis「payment-queue」线程");
                    Jedis jedis = jedisPool.getResource();
                    String json = null;
                    String sessionKey = null;
                    while (flag) {
                        //String json = jedis.blpop("")
                        List<String> jsonArr = jedis.brpop(0, "payment-queue");
                        for (int i = 0, len = jsonArr.size(); i < len; i++) {
                            if (i != 0) {
                                json = jsonArr.get(i);
                                if (null != json && !"".equals(json.trim())) {
                                    logger.debug("处理队列中消息：{}", json);
                                    JSONObject jsonObj = JSONObject.fromObject(json);
                                    String deviceId = jsonObj.getString("device_id");
                                    String userId = jsonObj.getString("user_id");
                                    String nickname = jsonObj.getString("nickname");
                                    String headerIcon = jsonObj.getString("header_icon");
                                    if (null != deviceId && null != userId && null != headerIcon) {
                                        Set<String> deviceSet = deviceMap.get(PREFIX_DEVICE_MAP + deviceId);
                                        if (null != deviceSet) {
                                            Iterator<String> it = deviceSet.iterator();
                                            while (it.hasNext()) {
                                                sessionKey = it.next();
                                                SessionManager.sendMessage(sessionKey, new NotifyMachineStatusMsg(deviceId, userId, nickname, headerIcon, "2"));
                                                logger.debug("PUT Message「Player,sessionKey={}」:{}", sessionKey, new Gson().toJson(new NotifyMachineStatusMsg(deviceId, userId, nickname, headerIcon, "2")));
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }).start();
            //从redis中获取离开队列，发送机器空闲状态信息
            new Thread(new Runnable() {
                @Override
                public void run() {
                    logger.debug("启动监听redis「leave-queue」线程");
                    Jedis jedis = jedisPool.getResource();
                    String json = null;
                    String sessionKey = null;
                    while (flag) {
                        //String json = jedis.rpop("leave-queue");
                        List<String> jsonArr = jedis.brpop(0, "leave-queue");
                        for (int i = 0, len = jsonArr.size(); i < len; i++) {
                            if (i != 0) {
                                json = jsonArr.get(i);
                                if (null != json && !"".equals(json.trim())) {
                                    logger.debug("处理队列中消息：{}", json);
                                    JSONObject jsonObj = JSONObject.fromObject(json);
                                    String deviceId = jsonObj.getString("device_id");
                                    String userId = jsonObj.getString("user_id");
                                    String nickname = jsonObj.getString("nickname");
                                    String headerIcon = jsonObj.getString("header_icon");
                                    if (null != deviceId) {
                                        Set<String> deviceSet = deviceMap.get(PREFIX_DEVICE_MAP + deviceId);
                                        if (null != deviceSet) {
                                            Iterator<String> it = deviceSet.iterator();
                                            while (it.hasNext()) {
                                                sessionKey = it.next();
                                                SessionManager.sendMessage(sessionKey, new NotifyMachineStatusMsg(deviceId, userId, nickname, headerIcon, "1"));
                                                logger.debug("PUT Message「Player,sessionKey={}」:{}", sessionKey, new Gson().toJson(new NotifyMachineStatusMsg(deviceId, userId, nickname, headerIcon, "1")));
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        //{"room_id":""}
                    }
                }
            }).start();

            //关闭服务器后调用
            final NotifyServer server = notifyServer;
            Runtime.getRuntime().addShutdownHook(new Thread() {
                @Override
                public void run() {
                    try {
                        server.setIsOnline(GameServer.OFFLINE);
                        notifyServerService.updateServer(server);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });

            Runtime.getRuntime().addShutdownHook(new Thread() {
                @Override
                public void run() {
                    flag = false;
                }
            });

        } catch (Exception e) {
            logger.error("GameServer服务端启动异常：", e);
        }
    }

}
